#coding=utf-8
"""DON'T FORGET TO CHANGE:
sandbox. -> freebase.
"""


import hashlib
import freebase
import simplejson
import logging
import freebase.sandbox as sandbox
from app_settings import *
from ragendja.template import render_to_string
from django.http import HttpResponseBadRequest

class InvalidCompanyID(Exception):
    """
    Company with specified ID not found in Freebase BiovenTurist
    directory
    """
    def __str__(self):
        return "Company with specified ID doesn't exist"


class RetrieverInterface(object):
    """
    Retriever interface
    """
    def query(self, query):
        raise NotImplementedError
    def get(self):
        raise NotImplementedError


class SandboxRetriever(RetrieverInterface):
    """
    Freebase Sandbox retriever. It doesn't use caching.
    """

    def query(self, query):
        self._q = query
        return self

    def get(self):
        response = list(sandbox.mqlread(self._q))
        if not len(response)>0:
            raise InvalidCompanyID
        result = response
        return result


class FreeBaseRetriever(RetrieverInterface):
    """
    Caching FreeBase Retriever
    It retrieves information from FreeBase, storing query results in the
    cache
    """
    def __init__(self):
        self._c = {} # Cache

    def query(self, query):
        self._q = query
        return self

    def get(self):
        md5 = hashlib.md5()
        md5.update(simplejson.dumps(self._q))
        digest = md5.hexdigest()
        result = None
        if self._c.has_key(digest):
            result = self._c[digest]
        else:
            response = list(sandbox.mqlread(self._q))
            if not len(response)>0:
                raise InvalidCompanyID
            self._c[digest] = response
            result = response

        return result


class CompanyWriter(object):
    """Write information about Company to freebase
    """
    def __init__(self, retriever, id):
        if not isinstance(retriever, RetrieverInterface):
            raise TypeError('Expected RetrieverInterface')
        self._r = retriever
        self._id = id

    def _check_absent_keys(self, request, keys):
        """Check if request data has specified keys

        Return:
            False if all keys are exists in request
            True if one or few keys are absent
        """
        for key in keys:
            if not request.POST.has_key(key):
                return True
        return False

    def area_of_expertise(self, request):
        pass
        
    def overview(self, request):
        """Write overview of Company"""
        if self._check_absent_keys(request, ("value", "company_id", "article_name")):
            return HttpResponseBadRequest("Some keys are absent")
        sandbox.login(USERNAME, PASSWORD)
        value = request.POST.get("value", "").encode("utf-8")
        if not value:
            return HttpResponseBadRequest("No document content")
        uploaded_content = sandbox.upload(value, "text/plain")
        query = {
            "id": request.POST["company_id"],
            "create":"unless_exists",
            "type":"/common/topic",
            "name": request.POST["company_name"],
            "id": None,
            "article" : {
                "create":"unless_exists",
                "type":"/common/document",
                "id": None,
                "content":uploaded_content["id"]
            }
        }
        result = sandbox.mqlwrite(query)
        sandbox.logout()
        return sandbox.raw(result["article"]["content"])

    def ticker_symbol(self, request):
        """Write NASDAQ ticker symbol of Company"""
        if self._check_absent_keys(request, ("value", "company_id",)):
            return HttpResponseBadRequest("Some keys are absent")
        if len(request.POST["value"].split("|"))!=3:
            return HttpResponseBadRequest("Incorrect ticker symbol posted. Should be name|type_id|type_name.")
        ticker_value, type, type_name = request.POST["value"].split("|")
        sandbox.login(USERNAME, PASSWORD)
        # fetch all NASDAQ ticker symbols of our company
        query = [{
            "type": "/business/stock_ticker_symbol",
            "stock_exchange": {"type": "/finance/stock_exchange", "id":type},
            "company": {"type": "/business/company", "id": request.POST["company_id"]},
            "id": None,
            "name": None
        }]
        r = sandbox.mqlread(query)
        ids = [k["id"] for k in r]
        # delete all fetched tickers
        # as we replace old tickers with new ticker
        query = []
        for id in ids:
            query.append({
                "id": id,
                "type": {
                    "connect":"delete",
                    "id":"/business/stock_ticker_symbol"
                }
            })
        if query:
            r = sandbox.mqlwrite(query)
        # add new NASDAQ ticker entered by user
        query = {
            "id": request.POST["company_id"],
            "type": "/business/company",
            "ticker_symbol": {
                "create": "unless_connected",
                "type": "/business/stock_ticker_symbol",
                "stock_exchange": {
                    "id": type,
                    "type": "/finance/stock_exchange",
                },
                "ticker_symbol": ticker_value
            }
        }
        r = sandbox.mqlwrite(query)
        sandbox.logout()
        return "%s (%s)" % (ticker_value, type_name)
        

class CompanyReader(object):
    """
    Retrieve information about company from freebase
    """
    def __init__(self, retriever, id):
        if not isinstance(retriever, RetrieverInterface):
            raise TypeError("Expected RetrieverInterface")

        self._id = id[:-1] if id.endswith("/") else id
        self._q = \
            [{
                "id": str(self._id),
                "name": None,
                "type": "/base/bioventurist/science_or_technology_company",
                "/common/topic/image": [{"id": None, "optional": True}],
                "/business/company/company_type": None,
                "/common/topic/article":
                    [{"limit": 1, "id" : None, "optional": True, "timestamp":None, "sort":"-timestamp"}],
                "/common/topic/webpage":
                    [{"limit": 1, "id": None, "uri": None, "optional": True}],
                "has:area_of_expertise":
                    [{"id": None, "name": None, "optional": True}],
                "has:develops_treatments_for_disease":
                    [{"id": None, "name": None, "optional": True}],
                "/business/company/founded": {"value":None, "optional": True},
                "/business/company/headquarters":
                    [{"optional":True,
                      "*":[],
                      "citytown" : {"optional": True, "id": None, "guid": None, "name": None},
                      "state_province_region":{"optional": True, "id": None, "guid": None, "name": None},
                      "street_address":[],
                      "postal_code":{"optional": True, "id": None, "guid": None, "name": None}}],
                "/business/company/industry":
                    [{"name": None, "optional": True}],
                "/business/company/ticker_symbol":
                    [{"optional": True, "type": "/business/stock_ticker_symbol", "stock_exchange": {"name": None, "id": None}, "*": None}],
                "investment_round": [{"*": None, "optional": True}],
                "products":
                    [{
                            "*": None,
                            "/common/topic/article": [{"limit": 1, "id" : None, "optional": True}],
                            "optional": True,
                            "sales": [{"*": None, "optional": True}],
                            "developed_by":[{"name": None, "id": None, "optional": True}],
                            "/base/bioventurist/bv_therapeutic/indication_or_disease":
                                [{
                                    "guid": None,
                                    "id": None,
                                    "name": None,
                                    "disease": {"name": None, "id": None, "guid": None, "optional": True},
                                    "optional": True,
                                    "phase_of_development": None
                                    }]
                            }],
             }]

        self.response = retriever.query(self._q).get()

    def get_title(self):
        """
        Title of company
        """
        return self.response[0]['name']

    title = property(get_title)


    @property
    def id(self):
        """
        ID of company
        """
        return self.response[0]['id']


    def get_overview(self):
        """
        Overview (article) of company
        """

        overview = ''
        if self.response[0].has_key('/common/topic/article') and len(self.response[0]['/common/topic/article'])>0:
            overview = sandbox.raw(self.response[0]['/common/topic/article'][0]['id'])
        return overview

    overview = property(get_overview)

    def get_areas_of_expertise(self):
        """
        Area of expertise of company as HTML with links (<a/>)
        """
        areas = []
        if self.response[0].has_key("has:area_of_expertise") and len(self.response[0]["has:area_of_expertise"])>0:            
             areas = [{"id": e["id"], "name": e["name"]} for e in self.response[0]["has:area_of_expertise"]]
        return areas

    areas_of_expertise = property(get_areas_of_expertise)

    def get_medical_focuses(self):
        """
        Medical focuses of company as HTML with links (<a/>)
        """
        medical_focuses = []
        if self.response[0].has_key('has:develops_treatments_for_disease') and len(self.response[0]['has:develops_treatments_for_disease'])>0:
            for e in self.response[0]['has:develops_treatments_for_disease']:
                medical_focuses.append('<a href="/disease%s">%s</a>' % (e['id'], e['name']))
        return ', '.join(medical_focuses)

    medical_focuses = property(get_medical_focuses)

    def get_date_founded(self):
        """
        Date when company was founded
        """
        date_founded = ''
        if self.response[0].has_key('/business/company/founded'):
            date_founded = self.response[0]['/business/company/founded']['value']
        return date_founded

    date_founded = property(get_date_founded)

    def get_headquarters(self):
        """
        List of headquearter of a company
        """
        headquarters = []
        if self.response[0].has_key('/business/company/headquarters') and len(self.response[0]['/business/company/headquarters'])>0:
            for e in self.response[0]['/business/company/headquarters']:
                headquarters.append(
                    ', '.join((' and '.join(e['street_address']), e['citytown']['name'], e['state_province_region']['name'], e['postal_code']['name']))
                )
        return '<br/>'.join(headquarters)

    headquarters = property(get_headquarters)

    def get_industries(self):
        """
        Industries of a company
        """
        industries = []
        if self.response[0].has_key('/business/company/industry') and len(self.response[0]['/business/company/industry'])>0:
            for e in self.response[0]['/business/company/industry']:
                industries.append(e['name'])
        return ', '.join(industries)

    industries = property(get_industries)

    def get_webpages(self):
        """
        Links to sites of company
        """
        webpages = []
        if self.response[0].has_key('/common/topic/webpage') and len(self.response[0]['/common/topic/webpage'])>0:
            for e in self.response[0]['/common/topic/webpage']:
                webpages.append('<a href="%s">%s</a>' % (e['uri'], e['uri']))
        return ', '.join(webpages)

    webpages = property(get_webpages)

    def get_company_type(self):
        """
        Type of a company
        """
        return self.response[0]['/business/company/company_type']

    company_type = property(get_company_type)

    def get_ticker_symbol(self):
        """
        Ticker symbol
        """
        #ticker_symbol = None
        #if self.response[0].has_key('/business/company/ticker_symbol'):
            #for e in self.response[0]['/business/company/ticker_symbol']:
                #if e['stock_exchange'] == 'NASDAQ':
                    #ticker_symbol = e['ticker_symbol']

        logging.debug(str([[ts["ticker_symbol"], ts["stock_exchange"]["id"]] for ts in self.response[0]['/business/company/ticker_symbol']]))
        return [[ts["ticker_symbol"], ts["stock_exchange"]["name"], ts["stock_exchange"]["id"]] for ts in self.response[0]['/business/company/ticker_symbol']]
        

    ticker_symbol = property(get_ticker_symbol)

    def get_investment_round(self):
        """
        Investment round (date, raised amount, a list of investors and
        web refernces)
        """
        investment_round = {'date': None, 'amount_raised': None, 'investors': None, 'web_reference': None}
        if self.response[0].has_key('investment_round') and self.response[0]['investment_round']:
            r = self.response[0]['investment_round'][0]
            investment_round['date'] = r['date']
            investment_round['investors'] = ', '.join(r['investors'])
            investment_round['amount_raised'] = int(r['amount_raised'])
            investment_round['web_reference'] = ', '.join(r['web_reference'])
        return investment_round

    investment_round = property(get_investment_round)

    def get_products(self):
        """
        All products of the company
        """
        if self.response[0].has_key('products') and self.response[0]['products']:
            return self.response[0]['products']

    products = property(get_products)

    def get_therapeutics_on_the_market(self):
        """
        Only Therapeutics on the market (not in development!)
        """
        therapeutics_on_the_market = []
        for p in self.products:
            phase = ''
            if (filter(lambda x: x.has_key('phase_of_development')  \
                       and x['phase_of_development']=='On the market',
                       p['/base/bioventurist/bv_therapeutic/indication_or_disease']) \
                or (p.has_key('stage_of_development') and p['stage_of_development']=='On the market')) \
                and '/base/bioventurist/bv_therapeutic' in p['type']:
                p['indication_or_disease'] = p[u'/base/bioventurist/bv_therapeutic/indication_or_disease']
                therapeutics_on_the_market.append(p)
        return therapeutics_on_the_market

    therapeutics_on_the_market = property(get_therapeutics_on_the_market)

    def get_products_on_the_market(self):
        """
        Only Non-Therapeutics products on the market
        """
        non_therapeutics_on_the_market = []
        for p in self.products:
            phase = ''
            if (filter(lambda x: x.has_key('phase_of_development')  \
                       and x['phase_of_development']=='On the market',
                       p['/base/bioventurist/bv_therapeutic/indication_or_disease']) \
                or (p.has_key('stage_of_development') and p['stage_of_development']=='On the market')) \
                and '/base/bioventurist/bv_therapeutic' not in p['type']:
                p['indication_or_disease'] = p[u'/base/bioventurist/bv_therapeutic/indication_or_disease']
                non_therapeutics_on_the_market.append(p)
        return non_therapeutics_on_the_market

    products_on_the_market = property(get_products_on_the_market)

    def get_therapeutics_in_development(self):
        """
        Only Therapeutics not on the market
        """
        therapeutics_in_development = []
        for p in self.products:
            phase = ''
            if (p.has_key('stage_of_development') and p['stage_of_development']=='In development') \
                and '/base/bioventurist/bv_therapeutic' in p['type']:
                p['indication_or_disease'] = p[u'/base/bioventurist/bv_therapeutic/indication_or_disease']
                therapeutics_in_development.append(p)
        return therapeutics_in_development

    therapeutics_in_development = property(get_therapeutics_in_development)

    def get_products_in_development(self):
        """
        Only products not on the market
        """
        products_in_development = []
        for p in self.products:
            phase = ''
            if (p.has_key('stage_of_development') and \
                p['stage_of_development']=='In development' and \
                '/base/bioventurist/bv_therapeutic' not in p['type'])\
                ^('/base/bioventurist/bv_therapeutic' not in p['type']): # XOR
                if p.has_key('/common/topic/article') and len(p['/common/topic/article'])>0:
                    p['article'] = sandbox.blurb(p['/common/topic/article'][0]['id'])
                p['indication_or_disease'] = p[u'/base/bioventurist/bv_therapeutic/indication_or_disease']
                products_in_development.append(p)

        return products_in_development

    products_in_development = property(get_products_in_development)

    def get_logo_dict(self):
        """
        Return dictionary cinatining information about comapny's logo:
            result['url'] -- full URL of thumbnail, e.g.
                             'http://freebase.com/api/trans/image_thumb/wikipedia/images/en_id/4609692'
            result['id'] -- if of logo, e.g. '/wikipedia/images/en_id/4609692'
        If no logo returns empty dict
        """
        result = {}
        if self.response[0].has_key('/common/topic/image') and self.response[0]['/common/topic/image']:
            img = self.response[0]['/common/topic/image'][0]
            result['id'] = img['id']
            result['url'] = ''.join(('http://freebase.com/api/trans/image_thumb', img['id']))
        return result

    logo = property(get_logo_dict)

